package cz.cuni.mff.d3s.arcas.generator.alloy

import cz.cuni.mff.d3s.arcas.intermediate.*

import java.util.*

class GeneratorExtensions {

	def alloyIdentifierNormalize(String text) {
		text.replace('.', '_');
	}
	
	def alloyName(Connector connector) {
		"C_" + connector.name.toFirstUpper
	}

	def alloyName(ConnectorEndpoint endpoint) {
		"EP_" + endpoint.name.alloyIdentifierNormalize.toFirstUpper
	}

	def alloyName(ConnectorFeature feature) {
		"F_" + feature.name.toFirstUpper
	}

	def alloyName(ConnectorFeatureValue featureValue) {
		"FV_" + featureValue.name.toFirstUpper
	}

	def alloyName(DeploymentDock dock) {
		"DD_" + dock.name.toFirstUpper
	}

	def alloyName(DistributionArchitecture da) {
		"DA_" + da.name.toFirstUpper
	}

	def alloyName(DistributionArchitectureRole role) {
		"R_" + role.name.toFirstUpper
	}

	def alloyName(DistributionArchitectureUnit unit) {
		"U_" + unit.name.toFirstUpper
	}

	def alloyName(ElementArchitecture ea) {
		"EA_" + ea.name.toFirstUpper
	}

	def alloyName(ElementArchitectureSubElement se) {
		"SE_" + se.name.toFirstUpper
	}

	def alloyName(ElementArchitectureFeature f) {
		"F_" + f.name.toFirstUpper
	}

	def alloyName(Port port) {
		switch (port.type) {
			case "LocalProvidedPort":
				"LPP_" + port.name.toFirstUpper
			case "LocalRequiredPort":
				"LRP_" + port.name.toFirstUpper
			case "RemotePort":
				"RP_" + port.name.toFirstUpper
			default:
				port.name.toFirstUpper
		}
	}

	def alloyName(Role role) {
		"R_" + role.name.toFirstUpper
	}

	def alloyName(Signature signature) {
		"S_" + signature.name.toFirstUpper
	}

	def alloyName(Subelement se) {
		"SE_" + se.name.toFirstUpper
	}

	def alloyNameA(String attribute) {
		if (attribute.startsWith("$")) {
			"A_" + attribute.substring(1).toFirstUpper
		} else {
			"A_" + attribute.toFirstUpper
		}
	}

	def alloyNameDa(String distributionArchitecture) {
		"DA_" + distributionArchitecture.toFirstUpper
	}

	def alloyNameDock(String dock) {
		"DD_" + dock.toFirstUpper
	}

	def alloyNameEa(String elementArchitecture) {
		"EA_" + elementArchitecture.toFirstUpper
	}

	def alloyNameEp(String component, String iface) {
		"EP_" + component.toFirstUpper + "_" + iface
	}

	def alloyNameF(String featureName) {
		"F_" + featureName.toFirstUpper
	}

	def alloyNameFv(String featureValue) {
		"FV_" + featureValue.toFirstUpper
	}

	/** Return port name for Alloy (e.g. including port type) by looking up specified port name in ports collection. */
	def alloyNamePort(String port, Iterable<Port> ports) {
		if (ports.filter(x|x.name == port).empty)
			port
		else
			ports.filter(x|x.name == port).head.alloyName
	}

	def alloyNameRole(String role) {
		"R_" + role.toFirstUpper
	}

	def alloyNameS(String signature) {
		"S_" + signature.toFirstUpper
	}

	def alloyNameSe(String subElement) {
		"SE_" + subElement.toFirstUpper
	}

	def alloyNameUnit(String unit) {
		"U_" + unit.toFirstUpper
	}

	def alloySet(Iterable<ElementArchitectureFeature> features) '''
		«IF features.empty»
			none«
		ELSE»
			«FOR f : features SEPARATOR " + "»«f.alloyName»«ENDFOR»«
		ENDIF»'''

	def alloySetFv(Iterable<ConnectorFeatureValue> featureValues) '''
		«IF featureValues.empty»
			none«
		ELSE»
			«FOR fv : featureValues SEPARATOR " + "»«fv.getFeatureValueNameWithAttributes»«ENDFOR»«
		ENDIF»'''

	def alloySetA(Iterable<String> attributes) '''
		«IF attributes.empty»
			none«
		ELSE»
			«FOR a : attributes SEPARATOR " + "»«a.alloyNameA»«ENDFOR»«
		ENDIF»'''

	def alloySetS(Iterable<String> signatures) '''
		«IF signatures.empty»
			none«
		ELSE»
			«FOR s : signatures SEPARATOR " + "»«s.alloyNameS»«ENDFOR»«
		ENDIF»'''

	def fileName(Connector connector) {
		connector.name + ".als"
	}

	def getFeatureValueNameWithAttributes(ConnectorFeatureValue fv) {
		var newName = fv.name.alloyNameFv
		for (attribute : fv.attributes)
			newName = newName + "_" + attribute.name + attribute.value.alloyIdentifierNormalize.toFirstUpper
		return newName
	}

	def getUniqueFeatures(IntermediateDocument doc) {
		var ret = new ArrayList<ElementArchitectureFeature>()

		for (feature : doc.elementArchitectures.map(x|x.features.filter(y|y.value != null)).flatten) {
			if (!ret.exists(x|x.value == feature.value))
				ret += feature
		}

		return ret
	}

}
